package fr.jade.fraclite;

import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.api.NoSuchInterfaceException;
import org.objectweb.fractal.api.Type;
import org.objectweb.fractal.api.control.IllegalBindingException;
import org.objectweb.fractal.api.control.IllegalContentException;
import org.objectweb.fractal.api.control.IllegalLifeCycleException;
import org.objectweb.fractal.api.factory.Factory;
import org.objectweb.fractal.api.factory.InstantiationException;
import org.objectweb.fractal.api.type.ComponentType;
import org.objectweb.fractal.api.type.InterfaceType;
import org.objectweb.fractal.deployment.local.api.IModule;
import org.objectweb.fractal.deployment.local.api.IModuleRepository;
import org.objectweb.fractal.util.Fractal;

import fr.jade.fraclite.factory.BasicGenericFactory;
import fr.jade.fraclite.type.BasicTypeFactory;

public class FracLite implements Factory {

	/**
	 * The bootstrap component.
	 */

	private static Component bootstrapComposite;

	private static Component bootstrapComponent;

	private static Component systemModuleComponent;

	private static Component moduleRepositoryComponent;

	private static Component packageRepositoryComponent;

	public static final String DEFAULT_CONFIGURATION_FILE_NAME = "FracLite.xml";

	public static final String DEFAULT_MODULE_REPOSITORY_FILE_NAME = "Repository.xml";

	// -------------------------------------------------------------------------
	// Implementation of the Factory interface
	// -------------------------------------------------------------------------

	/**
	 * @return <tt>null</tt>.
	 */

	public Type getFcInstanceType() {
		return null;
	}

	/**
	 * @return <tt>null</tt>.
	 */

	public Object getFcControllerDesc() {
		return null;
	}

	/**
	 * @return <tt>null</tt>.
	 */

	public Object getFcContentDesc() {
		return null;
	}

	public Component newFcInstance() {

		if (bootstrapComponent == null) {
			BasicTypeFactory typeFactory = new BasicTypeFactory();
			BasicGenericFactory genericFactory = new BasicGenericFactory();
			genericFactory.weaveableTF = typeFactory;

			try {
				ComponentType bootstrapCompositeType = typeFactory
						.createFcType(new InterfaceType[] {});

				bootstrapComposite = genericFactory.newFcInstance(
						bootstrapCompositeType, "composite", null);
				Fractal.getNameController(bootstrapComposite).setFcName(
						"bootstrapComposite");
			} catch (InstantiationException e) {
				e.printStackTrace();
				System.exit(0);
			} catch (NoSuchInterfaceException e) {
				e.printStackTrace();
				System.exit(0);
			}

			InterfaceType systemModuleServerInterface;
			try {
				systemModuleServerInterface = typeFactory.createFcItfType(
						"system-1.0.0",
						"org.objectweb.fractal.deployment.local.api.IModule",
						false, false, false);
				InterfaceType[] bootInterfaces = new InterfaceType[] { systemModuleServerInterface };

				ComponentType t = typeFactory.createFcType(bootInterfaces);
				systemModuleComponent = genericFactory.newFcInstance(t,
						"module",
						"fr.jade.fraclite.deployment.GenericModuleComponent");
				Fractal.getContentController(bootstrapComposite)
						.addFcSubComponent(systemModuleComponent);
				Fractal.getNameController(systemModuleComponent).setFcName(
						"system-1.0.0");
			} catch (InstantiationException e) {
				e.printStackTrace();
				System.exit(0);
			} catch (IllegalContentException e) {
				e.printStackTrace();
				System.exit(0);
			} catch (IllegalLifeCycleException e) {
				e.printStackTrace();
				System.exit(0);
			} catch (NoSuchInterfaceException e) {
				e.printStackTrace();
				System.exit(0);
			}

			try {
				// use the pre bootstrap component to create the real bootstrap
				// component
				InterfaceType mrItf = typeFactory
						.createFcItfType(
								"mr",
								"org.objectweb.fractal.deployment.local.api.IModuleRepository",
								true, false, false);

				InterfaceType systemModuleClientInterface = typeFactory
						.createFcItfType(
								"system-1.0.0",
								"org.objectweb.fractal.deployment.local.api.IModule",
								true, false, false);

				InterfaceType gfItf = typeFactory
						.createFcItfType(
								"generic-factory",
								"org.objectweb.fractal.deployment.local.api.IGenericFactoryWithModules",
								false, false, false);

				InterfaceType[] bootInterfaces = new InterfaceType[] { gfItf,
						mrItf, systemModuleClientInterface };

				ComponentType t = typeFactory.createFcType(bootInterfaces);
				bootstrapComponent = genericFactory
						.newFcInstance(t, "bootstrap",
								"fr.jade.fraclite.factory.BasicGenericFactoryWithModules");
				bindToBootstrapModule(bootstrapComponent);
				Fractal.getContentController(bootstrapComposite)
						.addFcSubComponent(bootstrapComponent);
			} catch (Exception e) {
				e.printStackTrace();
				System.exit(0);
			}

			try {
				InterfaceType prItf = typeFactory
						.createFcItfType(
								"pr",
								"org.objectweb.fractal.deployment.local.api.IPhysicalPackageRepository",
								false, false, true);
				InterfaceType gfItf = typeFactory.createFcItfType("gf",
						"org.objectweb.fractal.api.factory.GenericFactory",
						true, false, true);
				InterfaceType tfItf = typeFactory.createFcItfType("tf",
						"org.objectweb.fractal.api.type.TypeFactory", true,
						false, true);

				InterfaceType[] bootInterfaces = new InterfaceType[] { prItf,
						gfItf, tfItf };

				ComponentType t = typeFactory.createFcType(bootInterfaces);
				packageRepositoryComponent = genericFactory
						.newFcInstance(t, "primitive",
								"fr.jade.fraclite.deployment.BasicPhysicalPackageRepository");
				Fractal.getContentController(bootstrapComposite)
						.addFcSubComponent(packageRepositoryComponent);
				bindToBootstrapModule(packageRepositoryComponent);
				Fractal.getBindingController(packageRepositoryComponent)
						.bindFc(
								"gf",
								bootstrapComponent
										.getFcInterface("generic-factory"));
				Fractal.getBindingController(packageRepositoryComponent)
						.bindFc(
								"tf",
								bootstrapComponent
										.getFcInterface("type-factory"));
			} catch (InstantiationException e) {
				e.printStackTrace();
				System.exit(0);
			} catch (NoSuchInterfaceException e) {
				e.printStackTrace();
				System.exit(0);
			} catch (IllegalBindingException e) {
				e.printStackTrace();
				System.exit(0);
			} catch (IllegalLifeCycleException e) {
				e.printStackTrace();
				System.exit(0);
			} catch (IllegalContentException e) {
				e.printStackTrace();
				System.exit(0);
			}

			try {
				InterfaceType mrItf = typeFactory
						.createFcItfType(
								"mr",
								"org.objectweb.fractal.deployment.local.api.IModuleRepository",
								false, false, true);
				InterfaceType gfItf = typeFactory.createFcItfType("gf",
						"org.objectweb.fractal.api.factory.GenericFactory",
						true, false, true);
				InterfaceType tfItf = typeFactory.createFcItfType("tf",
						"org.objectweb.fractal.api.type.TypeFactory", true,
						false, true);

				InterfaceType prItf = typeFactory.createFcItfType("pr",
						"org.objectweb.fractal.api.type.TypeFactory", true,
						false, true);
				InterfaceType[] bootInterfaces = new InterfaceType[] { mrItf,
						gfItf, tfItf, prItf };

				ComponentType t = typeFactory.createFcType(bootInterfaces);
				moduleRepositoryComponent = genericFactory.newFcInstance(t,
						"primitive",
						"fr.jade.fraclite.deployment.BasicModuleRepository");
				Fractal.getContentController(bootstrapComposite)
						.addFcSubComponent(moduleRepositoryComponent);
				bindToBootstrapModule(moduleRepositoryComponent);
				Fractal.getBindingController(moduleRepositoryComponent).bindFc(
						"gf",
						bootstrapComponent.getFcInterface("generic-factory"));
				Fractal.getBindingController(moduleRepositoryComponent)
						.bindFc(
								"tf",
								bootstrapComponent
										.getFcInterface("type-factory"));
				Fractal.getBindingController(moduleRepositoryComponent).bindFc(
						"pr",
						packageRepositoryComponent
								.getFcInterface("pr"));
				Fractal.getBindingController(bootstrapComponent).bindFc("mr",
						moduleRepositoryComponent.getFcInterface("mr"));
				((IModuleRepository) moduleRepositoryComponent
						.getFcInterface("mr"))
						.addModuleComponent(systemModuleComponent);
			} catch (InstantiationException e) {
				e.printStackTrace();
				System.exit(0);
			} catch (NoSuchInterfaceException e) {
				e.printStackTrace();
				System.exit(0);
			} catch (IllegalBindingException e) {
				e.printStackTrace();
				System.exit(0);
			} catch (IllegalLifeCycleException e) {
				e.printStackTrace();
				System.exit(0);
			} catch (IllegalContentException e) {
				e.printStackTrace();
				System.exit(0);
			}

		}

		try {
			Fractal.getLifeCycleController(systemModuleComponent).startFc();
			Fractal.getLifeCycleController(bootstrapComponent).startFc();
			Fractal.getLifeCycleController(packageRepositoryComponent).startFc();
			Fractal.getLifeCycleController(moduleRepositoryComponent).startFc();
		} catch (IllegalLifeCycleException e) {
			e.printStackTrace();
			System.exit(0);
		} catch (NoSuchInterfaceException e) {
			e.printStackTrace();
			System.exit(0);
		}

		return bootstrapComponent;
	}

	private void bindToBootstrapModule(Component cmp) {
		IModule systemModuleInterface;
		try {
			systemModuleInterface = (IModule) systemModuleComponent
					.getFcInterface("system-1.0.0");
			Fractal.getBindingController(cmp).bindFc("system-1.0.0",
					systemModuleInterface);
		} catch (NoSuchInterfaceException e) {
			e.printStackTrace();
			System.exit(0);
		} catch (IllegalBindingException e) {
			e.printStackTrace();
			System.exit(0);
		} catch (IllegalLifeCycleException e) {
			e.printStackTrace();
			System.exit(0);
		}
	}
}
